package nagel_schreckenberg;

import java.io.Serializable;
import java.util.ArrayList;

public class PartialModel{

	private double[][] Tm;
	private double[] Rm;
	private double[] Nm;
	private PhasePolicy PIm;
	private double Em;
	private ArrayList<State> states;
	
	public PartialModel(ArrayList<State> s){
		states = s;
		Tm = new double[s.size()][s.size()];
		for(int a = 0; a < Tm.length; a++){
			for(int b = 0; b < Tm[0].length; b++){
				Tm[a][b] = 1/(double)s.size();
			}
		}
		Rm = new double[s.size()];
		Nm = new double[s.size()];
		Em = 0;
	}
	
	public void updateTm(int sn, int sp){
		for(State k : states){
			Tm[sn][states.indexOf(k)] = Tm[sn][states.indexOf(k)] + dTmPhi(sn, sp, states.indexOf(k));
		}
	}
	
	public void updateRm(int sn, double r){
		Rm[sn] = Rm[sn] + dRmPhi(sn, r);
	}
	
	public void updateNm(int sn){
		Nm[sn] = Math.min(Nm[sn]+1, Config.M);
	}
	
	public void updateEm(int sn, int sp, double r){
		Em = Em + Config.Em_P * (emPhi(sn, sp, r) - Em);
	}
	
	public void setPolicy(PhasePolicy p){
		PIm = p;
	}
	
	public PhasePolicy getPolicy(){
		return PIm;
	}
	
	public double getEm(){
		return Em;
	}
	
	public static int kroneckerDelta(int sp, int k){
		int kd = 0;
		if(sp == k){
			kd = 1;
		}
		return kd;
	}

	public double emPhi(int sn, int sp, double r){
		double sum = 0;
		int cnt = 0;
		for(State k : states){
			sum+= Math.pow(dTmPhi(sn, sp, cnt),2);
			cnt++;
		}
		double eP = cm(sn) * (Config.OMEGA*Math.pow(dRmPhi(sn, r),2) + (1-Config.OMEGA)*sum);
		return eP;
	}
	
	public double dTmPhi(int sn, int sp, int k){
		double dTP = 1/(Nm[sn]+1) * (kroneckerDelta(sp,k) - Tm[sn][k]);
		return dTP;
	}
	
	public double dRmPhi(int sn, double r){
		double dRP = 1/(Nm[sn]+1) * (r - Rm[sn]);
		return dRP;
	}
	
	public double cm(int sn){
		return Math.pow((Nm[sn]/Config.M),2);
	}

}
